import { MotaInterface } from "@/mota";
import BuildUtils from "@/mota/utils/BuildUtils"
import ScrollTool from "@/mota/tools/ScrollTool";
import { DrawSize, eventTypeList, UnitInfo } from "@/mota/data/MapDataUtils";
import Blockutils from "@/utils/BlockUtils";

export type BuildSelectInfo = [str: string, alpha?: boolean];

export default class BuildSelect extends ScrollTool<BuildSelectInfo> implements MotaInterface {

	public build: BuildUtils;

	public unit: UnitInfo | undefined = undefined;

	public pos: DrawSize | undefined = undefined;

	public ZIndex: number = 6;

	public block: Blockutils = new Blockutils();

	public state: undefined | "selectMove" | "selectScale" = undefined;

	public constructor(build: BuildUtils) {
		super({
			Left: 0,
			Top: 0,
			Width: 4,
			Height: 11,
			Padding: 0.1,
			ItemWidth: 4 - 0.2 - 0.1,
			ItemHeight: 0.6,
			ItemPadding: 0.1,
			List: new Array(4 + 2 + eventTypeList.length).fill(null),
			ScrollWidth: 0.1,
		});
		this.build = build;
	}

	public get isOpen() {
		return this.block.IsBlockUp;
	}

	public Open(info: UnitInfo): Promise<void> {
		return this.block.Wait(async () => {
			this.unit = info;
		}, () => {
			this.unit = undefined;
			this.pos = undefined;
			this.state = undefined;
		});
	}

	public DeleteUnit(info: UnitInfo) {
		this.unit = undefined;
		this.pos = undefined;
	}

	public InView(): boolean {
		const { isOpen } = this;
		return isOpen;
	}

	public JudgeKey: MotaInterface["JudgeKey"] = (keyUtils): void => {
		if (!this.InView()) { return; }

		const { state, unit, build, SelectIndex } = this;

		if (state !== undefined) { return; }

		for (const key of keyUtils.keyHistory) {
			if (key === "Escape") {
				this.block.Release();
				keyUtils.delete(key);
			}
			else if (key === "Backspace" || key === "Delete") {
				build.DeleteUnit(<UnitInfo>unit)
				keyUtils.delete(key);
			}
			else if (key === "ArrowUp") {
				this.SelectLast(true);
				keyUtils.delete(key);
			}
			else if (key === "ArrowDown") {
				this.SelectNext(true);
				keyUtils.delete(key);
			}
			else if (key === "Enter" || key === " ") {
				if (SelectIndex !== undefined) {
					this.handleSelect();
					keyUtils.delete(key);
				}
			}
		}
	}

	public click: MotaInterface["click"] = ([tx, ty], posf) => {

		const { state, build } = this;
		const { range, buildState } = build;

		if (build.isOpen && buildState === "none" && !this.isOpen && range === "draw") {
			const unit = build.GetUnit(tx - 4, ty);
			if (unit !== undefined && unit.length > 0) {
				if (state === undefined) {
					build.buildState = "append";
					this.Open(unit[0]).then(() => {
						build.buildState = "none";
					});
				}
			} else {
				this.block.Release();
			}
		}

		if (!this.InView()) { return; }

		if (range === "draw") {
			const unit = build.GetUnit(tx - 4, ty);
			if (unit !== undefined && unit.length > 0) {
				if (state === undefined) {
					this.unit = unit[0];
				}
			} else {
				this.block.Release();
			}
		} else if (range === "map") {
			if (state === undefined) {
				if (this.unit !== undefined) {
					this.SelectItem = this.GetItemByPos(...posf);
					this.handleSelect();
				}
			}
		} else if (range === undefined) {
			if (state === undefined) {
				this.block.Release();
			}
		}
	}

	public handleSelect() {
		const { unit, SelectIndex } = this;
		if (unit === undefined || SelectIndex === undefined) { return; }
		if (SelectIndex === 1) {
			unit[1] = !unit[1];
		} else if (SelectIndex === 3) {
			unit[3] = unit[3] === "first" ? "run" : "first";
		} else if (SelectIndex >= 5) {
			const event = unit[4];
			const list = eventTypeList;
			const eventI = SelectIndex - 5;
			if (eventI >= 0 && eventI < list.length) {
				const [type] = list[eventI];
				if (event === undefined) {
					unit[4] = new Set([type])
				} else {
					if (event.has(type)) {
						event.delete(type);
					} else {
						event.add(type);
					}
				}
			}
		}
	}

	public mousedown: MotaInterface["mousedown"] = ([tx, ty]) => {
		if (!this.InView()) { return; }

		const { state, build, unit } = this;
		const { range, Mota: { key: { keyMap } } } = build;

		if (state === undefined && unit !== undefined && range === "draw") {
			if (!keyMap.has("Shift")) {
				const info = build.GetUnit(tx - 4, ty);
				if (info !== undefined && info[0] === unit) {
					this.pos = [tx, ty];
					this.state = "selectMove";
				}
			} else {
				const info = build.GetUnit(tx - 4, ty);
				if (info !== undefined && info[0] === unit) {
					this.pos = unit[2];
					this.state = "selectScale";
				}
			}
		}
	}

	public mousemove: MotaInterface["mousemove"] = ([tx, ty]) => {
		if (!this.InView()) { return; }

		const { state, build, unit, pos } = this;
		const { range } = build;

		if (state === "selectMove" && range === "draw" && unit !== undefined) {
			const size = unit[2];
			if (size.length === 2) {
				unit[2] = [tx - 4, ty];
			} else if (pos !== undefined) {
				const [sax, say, sbx, sby] = size;
				const [px, py] = pos;
				const mx = tx - px;
				const my = ty - py;
				const tax = sax + mx;
				const tay = say + my;
				const tbx = sbx + mx;
				const tby = sby + my;
				if (build.JudgeRangeDraw(tax, tay) && build.JudgeRangeDraw(tbx, tby)) {
					unit[2] = [tax, tay, tbx, tby];
					this.pos = [tx, ty];
				}
			}
		}
		else if (state === "selectScale" && range === "draw" && unit !== undefined) {
			if (pos !== undefined) {
				const [x, y] = pos;
				let nx = tx - 4;
				let ny = ty;
				if (nx < x) { nx = x; }
				if (ny < y) { ny = y; }
				if (range === "draw") {
					unit[2] = (x === nx && y === ny) ? [x, y] : [x, y, nx, ny];
				} else if (range === undefined) {
					unit[2] = [x, y];
				}
			}
		}
	}

	public mouseup: MotaInterface["mouseup"] = () => {
		if (!this.InView()) { return; }

		const { state, build } = this;
		const { range } = build;
		if (state === "selectMove") {
			this.state = undefined;
		}
		if (state === "selectScale" && range === "draw") {
			this.state = undefined;
		}
	}

	public mousewheel: MotaInterface["mousewheel"] = (delta: number) => {
		if (!this.InView()) { return; }

		const { state, build } = this;
		if (state === undefined || state === "selectMove") {
			const isDown = delta > 0;
			this.Progress += isDown ? 1 : -1;
		}
	}

	public Draw: MotaInterface["Draw"] = (draw) => {
		if (!this.InView()) { return; }

		const { _2d } = draw;
		const { unit } = this;
		if (unit === undefined) { return; }

		_2d.save();
		_2d.fillStyle = "#FFFFFF";
		draw.SetFont(400, 1 / 3, "Mota");
		_2d.textAlign = "left";
		_2d.textBaseline = "top";
		_2d.strokeStyle = "#00FF00";
		draw.SetLineWidth(1 / 16);

		type DrawLList = [str: string, alpha?: boolean];
		const [name, show, size, state, event] = unit;
		this.List.Value = [
			[`单位：${name}`],
			[`是否显示：${show ? "是" : "否"}`],
			[`绘制大小：[${size.join(",")}]`],
			[`图像状态：${state === "first" ? "第一帧" : state === "run" ? "播放" : "未知"}`],
			[`触发类型列表：[`],
			...eventTypeList.map(item => {
				const hasEvent = event && event.has(item[0]);
				return <DrawLList>[`  ${item[1]}：${hasEvent ? "开" : "关"}`, !hasEvent];
			}),
			[`]`],
		];

		const itemList = this.GetItemsSize();
		itemList.forEach(([[str, alpha], isSelect, [x, y, ,], borderSize]) => {
			_2d.globalAlpha = 1;
			if (isSelect) {
				draw.strokeRect(...borderSize);
			}
			_2d.globalAlpha = alpha ? 0.5 : 1;
			draw.fillText(str, x, y);
		});

		/** 滚动条 */
		_2d.restore();
	}
}
